import mqtt_connect
import make_json
import ppp_connect
import wifi_connect
import device_cache
import threading
import json
import time
import common_func
import logging

from common_func import print_with_location
from common_func import ConnectionCode
from common_func import ConnectionStatus

from ppp_connect import PPP
from ppp_connect import ConnectionStatus

from wifi_connect import WiFi

# from wifi_connect import WiFi
from device_cache import NetworkConfigDB
from mqtt_connect import NanoMQClient
from make_json import NetworkJSONBuilder


class topic_handler:

    _instance = None
    _lock = threading.Lock()

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            with cls._lock:
                if not cls._instance:
                    cls._instance = super(topic_handler, cls).__new__(cls)
        return cls._instance

    def __init__(self):
        if hasattr(self, "_initialized") and self._initialized:
            return  # 防止重复初始化
        self.network_config_db = NetworkConfigDB()

        sub_topics = [
            "lan/network/wifi/config/get",
            "lan/network/wifi/status/get",
            "lan/network/wifi/config/push",
            "lan/network/wifi/scan/push",
            "lan/network/4g/config/get",
            "lan/network/4g/config/push",
            "lan/network/4g/status/get",
        ]

        self.mqtt = NanoMQClient(sub_topics=sub_topics)
        self.mqtt.register_topic_handler(
            "lan/network/wifi/config/get", self.handler_wifi_config_get
        )
        self.mqtt.register_topic_handler(
            "lan/network/wifi/status/get", self.handler_wifi_status_get
        )
        self.mqtt.register_topic_handler(
            "lan/network/wifi/config/push", self.handler_wifi_config_push
        )
        self.mqtt.register_topic_handler(
            "lan/network/wifi/scan/push", self.handler_wifi_scan_push
        )
        self.mqtt.register_topic_handler(
            "lan/network/4g/config/get", self.handler_4g_config_get
        )
        self.mqtt.register_topic_handler(
            "lan/network/4g/config/push", self.handler_4g_config_push
        )
        self.mqtt.register_topic_handler(
            "lan/network/4g/status/get", self.handler_4g_status_get
        )

        # 构造ppp对象
        self.ppp = PPP(status_callback=self.handler_network_status_report)
        # 构造wifi对象
        row = self.network_config_db.get_wifi_config(
            self.network_config_db.get_network_type_id("WiFi")
        )

        ssid = ""
        password = ""
        security = ""
        if row:
            ssid = row["ssid"]
            password = row["password"]
            security = row["security"]
        self.wifi = WiFi(
            status_callback=self.handler_network_status_report,
            ssid=ssid,
            password=password,
            security=security,
        )

        # self.mqtt.test_topic()
        # 获取配置信息
        mobile_net_enable_config, mobile_net_connect_enable = self.get_connect_config(
            "4G"
        )

        wifi_enable_config, wifi_connect_enable = self.get_connect_config("WiFi")

        is_mobile_net_connect = False
        is_wifi_net_connect = False
        if mobile_net_enable_config and mobile_net_connect_enable:
            is_mobile_net_connect = True

        if wifi_enable_config and wifi_connect_enable:
            is_wifi_net_connect = True

        if is_wifi_net_connect and is_mobile_net_connect:
            self.handler_network_status_report(
                status=3,
                hwt_ype="4G Wifi",
                ssid=None,
                error_msg="both wifi and 4g the enable config are true",
                error_code=ConnectionCode.CONFIG_ERROR.value,
            )
        elif is_wifi_net_connect:
            self.wifi.connect(ssid, password, security)

        elif is_mobile_net_connect:
            self.ppp.connect()

        # 根据它们的使能启动对应的模块

        # wifi也是一样都获取对应的配置信息，如果两个配置信息冲突了，那么上报错误

    def handler_wifi_config_get(self, payload):
        data = json.loads(payload)
        trans_id = data["transId"]
        # 从数据库中获取对应的配置信息

        # 拿到enable和enableToConnect
        wifi_enable_config, wifi_connect_enable = self.get_connect_config("WiFi")

        # 拿到ssid，password，security
        row = self.network_config_db.get_wifi_config(
            self.network_config_db.get_network_type_id("WiFi")
        )
        ssid = ""
        password = ""
        security = ""
        if row:
            ssid = row["ssid"]
            password = row["password"]
            security = row["security"]

        root = NetworkJSONBuilder(trans_id=trans_id).build_wifi_config_get_reply(
            enable=wifi_enable_config,
            enableToConnect=wifi_connect_enable,
            ssid=ssid,
            password=password,
            security=security,
        )
        self.mqtt.publish(json.dumps(root), topic="lan/network/wifi/config/getReply")

    def handler_wifi_status_get(self, payload):
        data = json.loads(payload)
        trans_id = data["transId"]

        row = self.network_config_db.get_wifi_config(
            self.network_config_db.get_network_type_id("WiFi")
        )
        ssid = None
        if row:
            ssid = row["ssid"]
            ip = self.wifi.get_wifi_ip()
            rssi = 0
            # 获取wifi的ip和信号强度
            wifi_lists = self.wifi.scan_wifi_list()
            if wifi_lists:
                for wifi_list in wifi_lists:
                    if wifi_list["ssid"] == ssid:
                        rssi = wifi_list["rssi"]
                        break
            root = NetworkJSONBuilder(trans_id=trans_id).build_wifi_config_status_reply(
                ssid=ssid,
                rssi=rssi,
                ip=ip,
                status=self.wifi.get_status,
                interface="wlan0",
            )
            self.mqtt.publish(
                json.dumps(root), topic="lan/network/wifi/status/getReply"
            )
        else:
            root = NetworkJSONBuilder(trans_id=trans_id).build_wifi_config_status_reply(
                ssid=ssid,
                rssi=0,
                ip="",
                status=self.wifi.get_status,
                interface="wlan0",
            )
            self.mqtt.publish(
                json.dumps(root), topic="lan/network/wifi/status/getReply"
            )

    def handler_wifi_config_push(self, payload):
        try:
            data = json.loads(payload)
            trans_id = data["transId"]

            # 拿到enable，enableToConnect,ssid，password，security
            enable = data["params"]["enable"]
            enable_to_connect = data["params"]["enableToConnect"]
            ssid = data["params"]["ssid"]
            password = data["params"]["password"]
            security = data["params"]["security"]

            # 缓存配置逻辑处理
            # if self.wifi.get_status.value == ConnectionStatus.CONNECTED.value:

            self.wifi.disconnect()
            time.sleep(1)

            # 写入数据库
            self.network_config_db.update_wifi_config(
                self.network_config_db.get_network_type_id("WiFi"),
                ssid=ssid,
                password=password,
                security=security,
            )

            self.network_config_db.set_enable_status(
                self.network_config_db.get_network_type_id("WiFi"), enable
            )

            self.network_config_db.set_connect_enable_status(
                self.network_config_db.get_network_type_id("WiFi"), enable_to_connect
            )

            # 当enable为0时，断开网口
            if enable is 0:
                self.wifi._bring_down_interface()

            # 连接指定wifi
            if enable and enable_to_connect:
                self.wifi.connect(ssid, password, security)

            root = NetworkJSONBuilder(trans_id=trans_id).build_wifi_config_push_reply()
            self.mqtt.publish(
                json.dumps(root), topic="lan/network/wifi/config/pushReply"
            )

        except Exception as e:
            print_with_location(f"[handler_wifi_config_push] {e}")
            root = NetworkJSONBuilder(
                trans_id=trans_id,
                code=ConnectionCode.ARGUMENTS_NONE.value,
                msg="json not valid",
            ).build_wifi_config_push_reply()
            self.mqtt.publish(
                json.dumps(root), topic="lan/network/wifi/config/pushReply"
            )
            return

    def handler_wifi_scan_push(self, payload):
        # 获取wifi列表并且返回
        try:
            data = json.loads(payload)
            trans_id = data["transId"]
            wifi_lists = self.wifi.scan_wifi_list()
            current_ssid = self.wifi.get_current_ssid
            wifi_status_list = []
            if wifi_lists:
                for wifi in wifi_lists:
                    status = (
                        self.wifi.get_status
                        if wifi.get("ssid") == current_ssid
                        else ConnectionStatus.DISCONNECTED.value
                    )
                    wifi_status_list.append(
                        {
                            "ssid": wifi.get("ssid", ""),
                            "security": wifi.get("security", ""),
                            "rssi": wifi.get("rssi", 0),
                            "status": status,
                        }
                    )
                root = NetworkJSONBuilder(trans_id=trans_id).build_wifi_scan_push_reply(
                    wifi_status_list
                )
                self.mqtt.publish(
                    json.dumps(root), topic="lan/network/wifi/scan/pushReply"
                )
            else:
                root = NetworkJSONBuilder(trans_id=trans_id).build_wifi_scan_push_reply(
                    wifi_status_list
                )
                self.mqtt.publish(
                    json.dumps(root), topic="lan/network/wifi/scan/pushReply"
                )

        except Exception as e:
            print_with_location(f"[handler_wifi_scan_push] {e}")
            root = NetworkJSONBuilder(trans_id=trans_id).build_wifi_scan_push_reply(
                wifi_status_list
            )
            self.mqtt.publish(json.dumps(root), topic="lan/network/wifi/scan/pushReply")

    def handler_4g_config_get(self, payload):
        # 获取transaid
        data = json.loads(payload)
        trans_id = data["transId"]

        # 从数据库获取配置信息
        enable_config, connect_enable = self.get_connect_config("4G")

        # if enable_config is None or connect_enable is None:
        #     print_with_location("[handler_4g_config_get] tack enable config error")
        #     enable_config = False

        root = NetworkJSONBuilder(trans_id=trans_id).build_4g_config_get_reply(
            enable_config, connect_enable
        )
        self.mqtt.publish(json.dumps(root), "lan/network/4g/config/getReply")

    def handler_4g_config_push(self, payload):
        # 解析payload，拿到enable，enableToConnect
        try:
            data = json.loads(payload)

            trans_id = data["transId"]

            # 获取参数值
            enable = data["params"]["enable"]
            enable_to_connect = data["params"]["enableToConnect"]

            if enable is None or enable_to_connect is None:
                print_with_location(
                    "[handler_4g_config_push] enable_config or connect_enable is None"
                )
                root = NetworkJSONBuilder(
                    trans_id=trans_id,
                    code=204,
                    msg="enable or enable_to_connect is none",
                ).build_4g_config_push_reply()

                self.mqtt.publish(json.dumps(root), "lan/network/4g/config/pushReply")

            # 缓存配置逻辑处理
            # if self.ppp.get_status.value == ConnectionStatus.CONNECTED.value:

            self.ppp.disconnect()
            time.sleep(1)

            # 写入数据库
            if self.set_connect_config("4G", enable, enable_to_connect) is False:
                root = NetworkJSONBuilder(
                    trans_id=trans_id,
                    code=400,
                    msg="enable or enable_to_connect is none or json not valid",
                ).build_4g_config_push_reply()
                self.mqtt.publish(json.dumps(root), "lan/network/4g/config/pushReply")

            if enable and enable_to_connect:
                self.ppp.connect()

            root = NetworkJSONBuilder(trans_id=trans_id).build_4g_config_push_reply()
            self.mqtt.publish(json.dumps(root), "lan/network/4g/config/pushReply")
        except Exception as e:
            print_with_location(f"[handler_4g_config_push] error: {e}")
            root = NetworkJSONBuilder(
                trans_id=trans_id,
                code=400,
                msg="enable or enable_to_connect is none or json not valid",
            ).build_4g_config_push_reply()

    def handler_4g_status_get(self, payload):
        # 获取transaid
        print_with_location("handler_4g_status_get IN >>>>")
        data = json.loads(payload)
        trans_id = data["transId"]

        ip = self.ppp.get_ppp_ip()
        csq = self.ppp.get_csq_value()
        ppp_status = self.ppp.get_status
        if ip is None:

            root = NetworkJSONBuilder(trans_id=trans_id).build_4g_status_reply(
                ppp_status.value
            )
            self.mqtt.publish(json.dumps(root), "lan/network/4g/status/getReply")
        else:
            root = NetworkJSONBuilder(trans_id=trans_id).build_4g_status_reply(
                status=ppp_status.value, csq=csq, ip=ip
            )
            self.mqtt.publish(json.dumps(root), "lan/network/4g/status/getReply")

    def handler_network_status_report(
        self,
        status: int,
        hwt_ype: str,
        ssid: str = None,
        error_code: int = None,
        error_msg: str = None,
    ):
        if status is ConnectionStatus.FAILED.value:
            root = NetworkJSONBuilder().build_network_status_update(
                status, hwt_ype, ssid, error_code, error_msg
            )
            self.mqtt.publish(json.dumps(root), "lan/network/status/update")

    def get_connect_config(self, config_name: str):
        try:
            enable_config = self.network_config_db.get_enable_status(
                self.network_config_db.get_network_type_id(config_name)
            )
            connect_enable = self.network_config_db.get_connect_enable_status(
                self.network_config_db.get_network_type_id(config_name)
            )

            return enable_config, connect_enable
        except Exception as e:
            print_with_location(f"[get_connect_config] error: {e}")
            return None, None

    def set_connect_config(
        self, config_name: str, enable: int, connect_enable: int
    ) -> bool:
        try:
            self.network_config_db.set_enable_status(
                self.network_config_db.get_network_type_id(config_name), enable
            )
            self.network_config_db.set_connect_enable_status(
                self.network_config_db.get_network_type_id(config_name), connect_enable
            )

            return True
        except Exception as e:
            print_with_location(f"[set_connect_config] error: {e}")
            return False
